﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using FIFP.Common;
using System.Collections.Generic;
using FIFP.DashBoard.Model;
using FIFP.DashBoard.Helper;
using System.Linq;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Telerik.Windows.Controls;
using System.ComponentModel.DataAnnotations;
using FIFP.DashBoard.Converters;
using System.Collections;
using System.Linq.Expressions;

namespace FIFP.DashBoard.ViewModel
{
    public class FilterVM : ViewModelCore, INotifyPropertyChanged, INotifyDataErrorInfo
    {
        #region Variables
        private DateTime displayEndDate = new DateTime(DateTime.Now.Year, 12, 31);
        private DateTime displayStartDate = new DateTime(DateTime.Now.Year, 1, 1);
        private DateTime startDate = new DateTime(DateTime.Now.Year, 1, 1);
        private DateTime endDate = new DateTime(DateTime.Now.Year, 12, 31);
        //public event EventHandler<CustomEventArgs<AppointmentGroup>> OnAppointmentDataCompleted;
        private List<string> selectedFluids = new List<string>();
        private List<string> selectedUnitTypes = new List<string>();
        private List<string> selectedLsdFluids = new List<string>();
        private List<string> selectedLsdUnitTypes = new List<string>();
        public event EventHandler<CustomEventArgs<AppointmentGroup>> OnAppointmentDataCompleted;
        public event EventHandler OnCombinedTowerClick;
        private readonly ICollection<ValidationResult> _validationResults;
        #endregion

        #region Properties

        public DateTime DisplayStartDate
        {
            get { return displayStartDate; }
            set { SetPropertyValue(() => DisplayStartDate, value, val => displayStartDate = val); }
        }

        public DateTime DisplayEndDate
        {
            get { return displayEndDate; }
            set { SetPropertyValue(() => DisplayEndDate, value, val => displayEndDate = val); }
        }

        [Display(Name = FIFPConstants.DISPLAY_STARTDATE)]
        [CustomValidation(typeof(ErrorValidation), FIFPConstants.VALIDATE_STARTDATE)]
        public DateTime StartDate
        {
            get { return startDate; }
            set
            {
                if (startDate != value)
                {
                    startDate = value;
                    NotifyPropertyChanged(() => StartDate);
                    NotifyPropertyChanged(() => EndDate);
                }
            }
        }

        [Display(Name = FIFPConstants.DISPLAY_ENDDATE)]
        [CustomValidation(typeof(ErrorValidation), FIFPConstants.VALIDATE_ENDATE)]
        public DateTime EndDate
        {
            get { return endDate; }
            set
            {
                if (endDate != value)
                {
                    endDate = value;
                    NotifyPropertyChanged(() => this.EndDate);
                    NotifyPropertyChanged(() => StartDate);
                }
            }
        }




        private ObservableCollection<FilterData> fluidList = new ObservableCollection<FilterData>();
        public ObservableCollection<FilterData> FluidList
        {
            get { return fluidList; }
            set { SetPropertyValue(() => FluidList, value, val => fluidList = val); }
        }

        private ObservableCollection<FilterData> lsdFluidList = new ObservableCollection<FilterData>();
        public ObservableCollection<FilterData> LsdFluidList
        {
            get { return lsdFluidList; }
            set { SetPropertyValue(() => LsdFluidList, value, val => lsdFluidList = val); }
        }

        private ObservableCollection<FilterData> unitTypeList = new ObservableCollection<FilterData>();
        public ObservableCollection<FilterData> UnitTypeList
        {
            get { return unitTypeList; }
            set { SetPropertyValue(() => UnitTypeList, value, val => unitTypeList = val); }
        }

        private ObservableCollection<FilterData> lsdUnitTypeList = new ObservableCollection<FilterData>();
        public ObservableCollection<FilterData> LsdUnitTypeList
        {
            get { return lsdUnitTypeList; }
            set { SetPropertyValue(() => LsdUnitTypeList, value, val => lsdUnitTypeList = val); }
        }

        private ObservableCollection<FilterData> facilityList = new ObservableCollection<FilterData>();
        public ObservableCollection<FilterData> FacilityList
        {
            get { return facilityList; }
            set { SetPropertyValue(() => FacilityList, value, val => facilityList = val); }
        }

        private ObservableCollection<FilterData> lsdFacilityList = new ObservableCollection<FilterData>();
        public ObservableCollection<FilterData> LsdFacilityList
        {
            get { return lsdFacilityList; }
            set { SetPropertyValue(() => LsdFacilityList, value, val => lsdFacilityList = val); }
        }


        private string selectedUnitType;
        public string SelectedUnitType
        {
            get { return selectedUnitType; }
            set { SetPropertyValue(() => SelectedUnitType, value, val => selectedUnitType = val); }
        }

        private string selectedFluidType;
        public string SelectedFluidType
        {
            get { return selectedFluidType; }
            set { SetPropertyValue(() => SelectedFluidType, value, val => selectedFluidType = val); }
        }


        private string selectedDivision;
        public string SelectedDivision
        {
            get { return selectedDivision; }
            set
            {
                if (selectedDivision != value)
                {
                    selectedDivision = value;
                    NotifyPropertyChanged(() => this.SelectedDivision);
                }
            }
        }

        private string selectedLsdDivision;
        public string SelectedLsdDivision
        {
            get { return selectedLsdDivision; }
            set
            {
                if (selectedLsdDivision != value)
                {
                    selectedLsdDivision = value;
                    NotifyPropertyChanged(() => this.SelectedLsdDivision);
                }
            }
        }

        private List<string> divisionList = new List<string>();
        public List<string> DivisionList
        {
            get { return divisionList; }
            set
            {
                if (divisionList != value)
                {
                    divisionList = value;
                    NotifyPropertyChanged(() => this.DivisionList);
                }
            }
        }



        private bool isFilterEnabled = false;
        public bool IsFilterEnabled
        {
            get { return isFilterEnabled; }
            set { SetPropertyValue(() => IsFilterEnabled, value, val => isFilterEnabled = val); }
        }

        private bool isDivisionEnabled = false;
        public bool IsDivisionEnabled
        {
            get { return isDivisionEnabled; }
            set { SetPropertyValue(() => IsDivisionEnabled, value, val => isDivisionEnabled = val); }
        }

        private Visibility isDateTimeVisibility = Visibility.Visible;
        public Visibility IsDateTimeVisibility
        {
            get { return isDateTimeVisibility; }
            set { SetPropertyValue(() => IsDateTimeVisibility, value, val => isDateTimeVisibility = val); }
        }

        private bool isCombinedTowerChecked = false;
        public bool IsCombinedTowerChecked
        {
            get { return isCombinedTowerChecked; }
            set { SetPropertyValue(() => IsCombinedTowerChecked, value, val => isCombinedTowerChecked = val); }
        }

        private Visibility isCombinedTowerVisibility = Visibility.Collapsed;
        public Visibility IsCombinedTowerVisibility
        {
            get { return isCombinedTowerVisibility; }
            set { SetPropertyValue(() => IsCombinedTowerVisibility, value, val => isCombinedTowerVisibility = val); }
        }

        private bool allCheckedUnchecked = false;
        public bool AllCheckedUnchecked
        {
            get { return allCheckedUnchecked; }
            set
            {
                if (allCheckedUnchecked != value)
                {
                    allCheckedUnchecked = value;
                    NotifyPropertyChanged(() => AllCheckedUnchecked);
                }
            }
        }

        private bool allLsdCheckedUnchecked = false;
        public bool AllLsdCheckedUnchecked
        {
            get { return allLsdCheckedUnchecked; }
            set
            {
                if (allLsdCheckedUnchecked != value)
                {
                    allLsdCheckedUnchecked = value;
                    NotifyPropertyChanged(() => AllLsdCheckedUnchecked);
                }
            }
        }

        #endregion

        #region Commands
        private ICommand _FilterByEnterKeyCommand;
        public ICommand FilterByEnterKeyCommand
        {
            get
            {
                return _FilterByEnterKeyCommand ??
                        (_FilterByEnterKeyCommand = new RelayCommand<object>(FilterAppointmentByFluidAndUnitTypeByEnterKey));
            }
        }


        private ICommand _FilterCommand;
        public ICommand FilterCommand
        {
            get
            {
                return _FilterCommand ??
                        (_FilterCommand = new RelayCommand<Button>(FilterAppointmentByFluidAndUnitType));
            }
        }



        private ICommand _DivisionSelectionCommand;
        public ICommand DivisionSelectionCommand
        {
            get
            {
                return _DivisionSelectionCommand ??
                        (_DivisionSelectionCommand = new RelayCommand<ComboBox>(DivisionFilter));
            }
        }

        private ICommand _CheckedUnCheckedEvent;
        public ICommand CheckedUnCheckedEvent
        {
            get
            {
                return _CheckedUnCheckedEvent ??
                        (_CheckedUnCheckedEvent = new RelayCommand<CheckBox>(CheckUnCheckAll));
            }
        }

        private ICommand _CheckedFluidEvent;
        public ICommand CheckedFluidEvent
        {
            get
            {
                return _CheckedFluidEvent ??
                        (_CheckedFluidEvent = new RelayCommand<CheckBox>(FluidFilter));
            }
        }

        private ICommand _CheckedUnitTypeEvent;
        public ICommand CheckedUnitTypeEvent
        {
            get
            {
                return _CheckedUnitTypeEvent ??
                        (_CheckedUnitTypeEvent = new RelayCommand<CheckBox>(UnitTypeFilter));
            }
        }

        private ICommand _CombinedTowerEvent;
        public ICommand CombinedTowerEvent
        {
            get
            {
                return _CombinedTowerEvent ??
                        (_CombinedTowerEvent = new RelayCommand<CheckBox>(FilterByCombinedTower));
            }
        }

        #endregion

        #region Constructor
        public FilterVM()
        {
            if (!DesignerProperties.IsInDesignTool)
            {
                _validationResults = new List<ValidationResult>();
                ServiceLocator.Get<ImportVM>().OnDivisionListDataCompleted += new EventHandler<CustomEventArgs<List<string>>>(FilterVM_OnDivisionListDataCompleted);
                LodaData();
            }
        }
        #endregion

        #region Load Fluid, UnitType and Faclity Type static Data
        private void LodaData()
        {
            FluidList = new ObservableCollection<FilterData>()
            {
                new FilterData() { FilterTypeId = FIFPConstants.FLUIDTYPE_OIL, FilterTypeName=FIFPConstants.FLUIDTYPE_OIL_DISPLAY ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.FLUIDTYPE_WATER, FilterTypeName=FIFPConstants.FLUIDTYPE_WATER_DISPLAY ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.FLUIDTYPE_GAS, FilterTypeName=FIFPConstants.FLUIDTYPE_GAS_DISPLAY ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.FLUIDTYPE_COMBINED, FilterTypeName=FIFPConstants.FLUIDTYPE_GAS_COMBINED,ItemChecked=false,ItemVisibility = Visibility.Visible}
            };

            LsdFluidList = new ObservableCollection<FilterData>()
            {
                new FilterData() { FilterTypeId = FIFPConstants.FLUIDTYPE_OIL, FilterTypeName=FIFPConstants.FLUIDTYPE_OIL_DISPLAY ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.FLUIDTYPE_WATER, FilterTypeName=FIFPConstants.FLUIDTYPE_WATER_DISPLAY ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.FLUIDTYPE_GAS, FilterTypeName=FIFPConstants.FLUIDTYPE_GAS_DISPLAY ,ItemChecked=false,ItemVisibility = Visibility.Visible},
            };

            UnitTypeList = new ObservableCollection<FilterData>()
            {
                new FilterData() { FilterTypeId = FIFPConstants.UNITTYPE_RADIAL, FilterTypeName=FIFPConstants.UNITTYPE_RADIAL ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_PIPELINE, FilterTypeName=FIFPConstants.UNITTYPE_PIPELINE ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_TOWER, FilterTypeName=FIFPConstants.UNITTYPE_TOWER ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_WELL, FilterTypeName=FIFPConstants.UNITTYPE_WELL ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_STRING, FilterTypeName=FIFPConstants.UNITTYPE_STRING ,ItemChecked=false,ItemVisibility = Visibility.Visible}
            };

            LsdUnitTypeList = new ObservableCollection<FilterData>()
            {
                new FilterData() { FilterTypeId = FIFPConstants.UNITTYPE_RADIAL, FilterTypeName=FIFPConstants.UNITTYPE_RADIAL ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_PIPELINE, FilterTypeName=FIFPConstants.UNITTYPE_PIPELINE ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_TOWER, FilterTypeName=FIFPConstants.UNITTYPE_TOWER ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_WELL, FilterTypeName=FIFPConstants.UNITTYPE_WELL ,ItemChecked=false,ItemVisibility = Visibility.Visible},
            };

            FacilityList = new ObservableCollection<FilterData>()
            {
                new FilterData() { FilterTypeId = FIFPConstants.UNITTYPE_PLATFORM, FilterTypeName=FIFPConstants.UNITTYPE_PLATFORM ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_COMPRESSOR, FilterTypeName=FIFPConstants.UNITTYPE_COMPRESSOR ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_SEPERATOR, FilterTypeName=FIFPConstants.UNITTYPE_SEPERATOR ,ItemChecked=false,ItemVisibility = Visibility.Visible},
                new FilterData() { FilterTypeId=FIFPConstants.UNITTYPE_MODULE, FilterTypeName=FIFPConstants.UNITTYPE_MODULE ,ItemChecked=false,ItemVisibility = Visibility.Visible}
            };

            LsdFacilityList = new ObservableCollection<FilterData>()
            {
                new FilterData() { FilterTypeId = FIFPConstants.UNITTYPE_PLATFORM, FilterTypeName=FIFPConstants.UNITTYPE_PLATFORM ,ItemChecked=false,ItemVisibility = Visibility.Visible},
            };

        }
        #endregion

        #region Get Division data from the corresponding view models
        void FilterVM_OnDivisionListDataCompleted(object sender, CustomEventArgs<List<string>> e)
        {
            if (e.Item != null)
            {
                DivisionList.Add("All");
                DivisionList.AddRange(e.Item);
                SelectedDivision = DivisionList[0];
                SelectedLsdDivision = DivisionList[0];
            }
        }
        #endregion

        #region Filter Appointment By Fluid and Unit Type
        private void FilterAppointmentByFluidAndUnitTypeByEnterKey(object e)
        {
            KeyEventArgs args = e as KeyEventArgs;
            if (args != null && args.Key == Key.Enter)
            {
                FilterAppoinements(true);
            }
        }


        private void FilterAppointmentByFluidAndUnitType(Button btnFilter)
        {
            FilterAppoinements(true);
        }

        public void FilterAppoinements(bool isReset)
        {
            List<FIFPAppointment> lstAppointments = new List<FIFPAppointment>();
            List<Unit> lstLSDLocations;
            if (DoDateValidation())
            {
                if (ServiceLocator.Get<MainPageVM>().IsImportChecked)
                {
                    //Applying Filter here is, we are updating new plans to ImportPlans. So we should reset overlap,lsd and optimization pages when apply filter.
                    //ServiceLocator.Get<OverlapVM_New>().Reset();
                    //ServiceLocator.Get<ShutdownMngVM>().Reset();
                    //ServiceLocator.Get<OptMngVM>().Reset();
                    FilterScenarioPlans();
                }
                else if (ServiceLocator.Get<MainPageVM>().IsOptimizationChecked && ServiceLocator.Get<MainPageVM>().IsLinkedSDChecked)
                {
                    lstLSDLocations = new List<Unit>();
                    lstAppointments = ServiceLocator.Get<ShutdownMngVM>().ShutdownPlans;
                    List<Unit> lsdActivities = new List<Unit>(ServiceLocator.Get<ShutdownMngVM>().LinkedShutdownLocations);
                    if (lsdActivities != null && lsdActivities.Count > 0)
                    {

                        if (selectedLsdFluids != null && selectedLsdFluids.Count > 0 && selectedLsdUnitTypes != null && selectedLsdUnitTypes.Count > 0)

                            lstLSDLocations = (from item in lsdActivities
                                               where selectedLsdFluids.Any(s => s.Equals(item.FluidType)) && selectedLsdUnitTypes.Any(s => s.Equals(item.UnitType))
                                               select item).ToList<Unit>();
                        else if (selectedLsdFluids != null && selectedLsdFluids.Count > 0)

                            lstLSDLocations = (from item in lsdActivities
                                               where selectedLsdFluids.Any(s => s.Equals(item.FluidType))
                                               select item).ToList<Unit>();
                        else if (selectedLsdUnitTypes != null && selectedLsdUnitTypes.Count > 0)
                            lstLSDLocations = (from item in lsdActivities
                                               where selectedLsdUnitTypes.Any(s => s.Equals(item.UnitType))
                                               select item).ToList<Unit>();
                        else
                            lstLSDLocations = lsdActivities;

                        List<Unit> filteredList = new List<Unit>();
                        if (SelectedLsdDivision != null && SelectedLsdDivision != "All")//"Division"
                        {
                            //Filter locations by selected division
                            foreach (Unit unit in lstLSDLocations)
                            {
                                FIFPAppointment appointment = lstAppointments.Where(s => s.UnitName == unit.UnitName && s.Division == SelectedLsdDivision).FirstOrDefault();
                                if (appointment != null)
                                    filteredList.Add(unit);
                            }
                        }
                        else
                            filteredList = lstLSDLocations;

                        if (isReset)
                        {
                            ServiceLocator.Get<ShutdownMngVM>().ResetFromFilter();
                            ServiceLocator.Get<ShutdownMngVM>().FilteredLSDLocations = new ObservableCollection<Unit>(filteredList);
                            LoadTimelineView(new List<FIFPAppointment>());
                        }
                        else
                            ServiceLocator.Get<ShutdownMngVM>().FilteredLSDLocations = new ObservableCollection<Unit>(filteredList);
                    }
                }
                else if (ServiceLocator.Get<MainPageVM>().IsOptimizationChecked && ServiceLocator.Get<MainPageVM>().IsOptMngChecked)
                {
                    lstLSDLocations = new List<Unit>();
                    lstAppointments = ServiceLocator.Get<OptMngVM>().OptimizedPlans;
                    List<Unit> lsdActivities = new List<Unit>(ServiceLocator.Get<OptMngVM>().LinkedShutdownLocations);
                    if (lsdActivities != null && lsdActivities.Count > 0)
                    {

                        if (selectedLsdFluids != null && selectedLsdFluids.Count > 0 && selectedLsdUnitTypes != null && selectedLsdUnitTypes.Count > 0)

                            lstLSDLocations = (from item in lsdActivities
                                               where selectedLsdFluids.Any(s => s.Equals(item.FluidType)) && selectedLsdUnitTypes.Any(s => s.Equals(item.UnitType))
                                               select item).ToList<Unit>();
                        else if (selectedLsdFluids != null && selectedLsdFluids.Count > 0)

                            lstLSDLocations = (from item in lsdActivities
                                               where selectedLsdFluids.Any(s => s.Equals(item.FluidType))
                                               select item).ToList<Unit>();
                        else if (selectedLsdUnitTypes != null && selectedLsdUnitTypes.Count > 0)
                            lstLSDLocations = (from item in lsdActivities
                                               where selectedLsdUnitTypes.Any(s => s.Equals(item.UnitType))
                                               select item).ToList<Unit>();
                        else
                            lstLSDLocations = lsdActivities;

                        List<Unit> filteredList = new List<Unit>();
                        if (SelectedLsdDivision != null && SelectedLsdDivision != "All")//"Division"
                        {
                            //Filter locations by selected division
                            foreach (Unit unit in lstLSDLocations)
                            {
                                FIFPAppointment appointment = lstAppointments.Where(s => s.UnitName == unit.UnitName && s.Division == SelectedLsdDivision).FirstOrDefault();
                                if (appointment != null)
                                    filteredList.Add(unit);
                            }
                        }
                        else
                            filteredList = lstLSDLocations;

                        if (isReset)
                        {
                            ServiceLocator.Get<OptMngVM>().ResetFromFilter();
                            ServiceLocator.Get<OptMngVM>().FilteredLSDLocations = new ObservableCollection<Unit>(filteredList);
                            LoadTimelineView(new List<FIFPAppointment>());
                        }
                        else
                            ServiceLocator.Get<OptMngVM>().FilteredLSDLocations = new ObservableCollection<Unit>(filteredList);
                    }
                }
            }
        }

        private void FilterScenarioPlans()
        {
            List<FIFPAppointment> lstAppointments = new List<FIFPAppointment>();
            List<FIFPAppointment> importActivities = new List<FIFPAppointment>();
            ServiceLocator.Get<ImportVM>().ImportPlans = importActivities = (from item in ServiceLocator.Get<ImportVM>().ScenarioPlans
                                                      where (item.Start >= StartDate || item.End <= EndDate)
                                                      select item).ToList<FIFPAppointment>();
            if (importActivities != null && importActivities.Count > 0)
            {
                if (selectedFluids != null && selectedFluids.Count > 0 && selectedUnitTypes != null && selectedUnitTypes.Count > 0)

                    lstAppointments = (from item in importActivities
                                       where selectedFluids.Contains(item.FluidType) && selectedUnitTypes.Contains(item.UnitType)
                                       select item).ToList<FIFPAppointment>();
                else if (selectedFluids != null && selectedFluids.Count > 0)

                    lstAppointments = (from item in importActivities
                                       where selectedFluids.Contains(item.FluidType)
                                       select item).ToList<FIFPAppointment>();
                else if (selectedUnitTypes != null && selectedUnitTypes.Count > 0)
                    lstAppointments = (from item in importActivities
                                       where selectedUnitTypes.Contains(item.UnitType)
                                       select item).ToList<FIFPAppointment>();
                else
                    lstAppointments = (from item in importActivities                                       
                                       select item).ToList<FIFPAppointment>();


                if (!string.IsNullOrEmpty(SelectedDivision) && SelectedDivision != "All")//"Division"
                {
                    if (SelectedDivision != null && SelectedDivision == "TSD")
                    {
                        List<string> oGCDactivityCodes = ServiceLocator.Get<ImportVM>().ActivityCodeDivisionList.Where(s => s.DivisionId == 5).Select(l => l.Name).ToList<string>();
                        lstAppointments = lstAppointments.Except(lstAppointments.Where(s => oGCDactivityCodes.Any(l => l.Equals(s.ActivityCode)))).ToList<FIFPAppointment>();
                    }
                    else
                        lstAppointments = (from item in lstAppointments
                                           where item.Division == SelectedDivision
                                           select item).ToList<FIFPAppointment>();
                }
                
                ServiceLocator.Get<ImportVM>().LoadTimelineView((from item in lstAppointments orderby item.nIndex ascending select item).ToList<FIFPAppointment>());
            }
        }

        #endregion

        #region DoValidation
        private bool DoDateValidation()
        {
            bool bRet = true;

            if (StartDate > EndDate)
            {
                bRet = false;
                NotifyPropertyChanged(() => StartDate);
            }
            else if (EndDate < StartDate)
            {
                bRet = false;
                NotifyPropertyChanged(() => EndDate);
            }
            else
            {
                NotifyPropertyChanged(() => StartDate);
                NotifyPropertyChanged(() => EndDate);
            }

            return bRet;
        }
        #endregion

        #region Division Filter
        private void DivisionFilter(ComboBox cmbDivision)
        {
            if (ServiceLocator.Get<MainPageVM>().IsOptimizationChecked && (ServiceLocator.Get<MainPageVM>().IsLinkedSDChecked || ServiceLocator.Get<MainPageVM>().IsOptMngChecked))
            {
                FilterAppoinements(false);
                /*
                List<FIFPAppointment> filteredAppointments = new List<FIFPAppointment>();
                List<FIFPAppointment> appointments = new List<FIFPAppointment>();

                if (ServiceLocator.Get<MainPageVM>().IsLinkedSDChecked)
                    appointments = ServiceLocator.Get<ShutdownMngVM>().ActivityListWithSelectedUnit;
                else if (ServiceLocator.Get<MainPageVM>().IsOptMngChecked)
                    appointments = ServiceLocator.Get<OptMngVM>().ActivityListWithSelectedUnit;

                if (appointments != null && appointments.Count > 0)
                {
                    if (SelectedLsdDivision != null && SelectedLsdDivision == "All")//"Division"
                        filteredAppointments = appointments;
                    else
                        filteredAppointments = (from item in appointments
                                                where item.Division == SelectedLsdDivision
                                                select item).ToList<FIFPAppointment>();
                }

                if (ServiceLocator.Get<MainPageVM>().IsOptimizationChecked && ServiceLocator.Get<MainPageVM>().IsLinkedSDChecked)
                {
                    ServiceLocator.Get<ShutdownMngVM>().FilteredActivityListWithSelectedUnit = new ObservableCollection<FIFPAppointment>(filteredAppointments.OrderBy(s => s.Start));
                    List<FIFPAppointment> lsdPlans = new List<FIFPAppointment>();
                    foreach (FIFPAppointment appointment in filteredAppointments)
                    {
                        lsdPlans.Add(appointment);
                        lsdPlans.AddRange(appointment.FilteredLsdPlans);
                    }
                    ServiceLocator.Get<ShutdownMngVM>().LoadTimelineView(lsdPlans);
                }
                else if (ServiceLocator.Get<MainPageVM>().IsOptimizationChecked && ServiceLocator.Get<MainPageVM>().IsOptMngChecked)
                {
                    ServiceLocator.Get<OptMngVM>().FilteredActivityListWithSelectedUnit = new ObservableCollection<FIFPAppointment>(filteredAppointments.OrderBy(s => s.Start));
                    List<FIFPAppointment> lsdPlans = new List<FIFPAppointment>();
                    foreach (FIFPAppointment appointment in filteredAppointments)
                    {
                        lsdPlans.Add(appointment);
                        lsdPlans.AddRange(appointment.FilteredLsdPlans);
                    }
                    ServiceLocator.Get<OptMngVM>().LoadTimelineView(lsdPlans);

                }*/
            }
            else
                FilterScenarioPlans();
        }
        #endregion

        #region LoadTimelineView
        private void LoadTimelineView(List<FIFPAppointment> plans)
        {
            AppointmentGroup appointmentGroup = new AppointmentGroup();
            List<ResourceType> lstResources = new List<ResourceType>();
            List<Resource> unitList = new List<Resource>();
            ResourceType unitType = new ResourceType("Unit");
            unitType.DisplayName = "Unit";
            unitType.Name = "Unit";

            foreach (FIFPAppointment appointment in plans)
            {
                Resource resource = new Resource() { ResourceName = appointment.UnitName, DisplayName = appointment.UnitName, ResourceType = unitType.Name };
                //unitList.Add(resource);
                if (!unitList.Contains(resource))
                {
                    unitList.Add(resource);
                }
                appointment.Resources.Add(resource);

                if (!string.IsNullOrEmpty(appointment.FluidType))
                {
                    switch (appointment.FluidType)
                    {
                        case FIFPConstants.FLUIDTYPE_OIL:
                            appointment.Category = (appointment.IsAppliedSimops) ? new Category("", new SolidColorBrush(new Color() { R = 0x3D, G = 0x3D, B = 0x3D, A = 0xFF })) : new Category("Oil", new SolidColorBrush(new Color() { R = 0xFF, G = 0x59, B = 0x59, A = 0xFF }));
                            break;
                        case FIFPConstants.FLUIDTYPE_COMBINED:
                            appointment.Category = (appointment.IsAppliedSimops) ? new Category("", new SolidColorBrush(new Color() { R = 0x3D, G = 0x3D, B = 0x3D, A = 0xFF })) : new Category("Combined", new SolidColorBrush(new Color() { R = 0x80, G = 0x0D, B = 0x54, A = 0xFF }));
                            break;
                        case FIFPConstants.FLUIDTYPE_WATER:
                            appointment.Category = (appointment.IsAppliedSimops) ? new Category("", new SolidColorBrush(new Color() { R = 0x3D, G = 0x3D, B = 0x3D, A = 0xFF })) : new Category("Water", new SolidColorBrush(new Color() { R = 0x4B, G = 0xAC, B = 0xC6, A = 0xFF }));
                            break;
                        case FIFPConstants.FLUIDTYPE_GAS:
                            appointment.Category = (appointment.IsAppliedSimops) ? new Category("", new SolidColorBrush(new Color() { R = 0x3D, G = 0x3D, B = 0x3D, A = 0xFF })) : new Category("Gas", new SolidColorBrush(new Color() { R = 0x93, G = 0xA8, B = 0x2A, A = 0xFF }));
                            break;
                        case FIFPConstants.TOWERTYPE_MANIFOLD:
                            appointment.Category = (appointment.IsAppliedSimops) ? new Category("", new SolidColorBrush(new Color() { R = 0x3D, G = 0x3D, B = 0x3D, A = 0xFF })) : new Category("Manifold", new SolidColorBrush(new Color() { R = 0x2E, G = 0x2E, B = 0x2E, A = 0xFF }));
                            break;
                        default:
                            break;
                    }
                }
            }

            appointmentGroup.Appointments = new List<FIFPAppointment>(plans);
            unitType.Resources.AddRange(unitList);
            lstResources.Add(unitType);


            appointmentGroup.ResourceTypes = lstResources;
            appointmentGroup.UnitList = unitList;

            if (OnAppointmentDataCompleted != null)
                OnAppointmentDataCompleted(this, new CustomEventArgs<AppointmentGroup>(appointmentGroup));

        }
        #endregion

        #region Reset Filter
        public void ResetFilterData()
        {
            selectedFluids = new List<string>();
            selectedUnitTypes = new List<string>();
            AllCheckedUnchecked = false;
            List<FilterData> fList = new List<FilterData>();
            if (FluidList != null && FluidList.Count > 0 && FluidList.Where(s => s.ItemChecked == true).Count() > 0)
            {
                fList = new List<FilterData>(FluidList);
                fList.ForEach(s => { s.ItemChecked = false; });
                FluidList = new ObservableCollection<FilterData>(fList);
            }

            if (FacilityList != null && FacilityList.Count > 0 && FacilityList.Where(s => s.ItemChecked == true).Count() > 0)
            {
                fList = new List<FilterData>(FacilityList);
                fList.ForEach(s => { s.ItemChecked = false; });
                FacilityList = new ObservableCollection<FilterData>(fList);
            }

            if (UnitTypeList != null && UnitTypeList.Count > 0 && UnitTypeList.Where(s => s.ItemChecked == true).Count() > 0)
            {
                fList = new List<FilterData>(UnitTypeList);
                fList.ForEach(s => { s.ItemChecked = false; });
                UnitTypeList = new ObservableCollection<FilterData>(fList);
            }
        }

        public void ResetLsdFilterData()
        {
            selectedLsdFluids = new List<string>();
            selectedLsdUnitTypes = new List<string>();
            AllLsdCheckedUnchecked = false;
            List<FilterData> fList = new List<FilterData>();

            if (LsdFluidList != null && LsdFluidList.Count > 0 && LsdFluidList.Where(s => s.ItemChecked == true).Count() > 0)
            {
                fList = new List<FilterData>(LsdFluidList);
                fList.ForEach(s => { s.ItemChecked = false; });
                LsdFluidList = new ObservableCollection<FilterData>(fList);
            }

            if (LsdFacilityList != null && LsdFacilityList.Count > 0 && LsdFacilityList.Where(s => s.ItemChecked == true).Count() > 0)
            {
                fList = new List<FilterData>(LsdFacilityList);
                fList.ForEach(s => { s.ItemChecked = false; });
                LsdFacilityList = new ObservableCollection<FilterData>(fList);
            }

            if (LsdUnitTypeList != null && LsdUnitTypeList.Count > 0 && LsdUnitTypeList.Where(s => s.ItemChecked == true).Count() > 0)
            {
                fList = new List<FilterData>(LsdUnitTypeList);
                fList.ForEach(s => { s.ItemChecked = false; });
                LsdUnitTypeList = new ObservableCollection<FilterData>(fList);
            }

        }
        #endregion

        #region Reset Filter
        public void CheckAllFilterData()
        {
            selectedFluids = new List<string>();
            selectedUnitTypes = new List<string>();
            List<FilterData> fList = new List<FilterData>();

            if (FluidList != null && FluidList.Count > 0)
            {
                fList = new List<FilterData>(FluidList);
                foreach (FilterData data in fList)
                {
                    data.ItemChecked = true;
                    selectedFluids.Add(data.FilterTypeId);
                }
                FluidList = new ObservableCollection<FilterData>(fList);
            }

            if (FacilityList != null && FacilityList.Count > 0)
            {
                fList = new List<FilterData>(FacilityList);
                foreach (FilterData data in fList)
                {
                    data.ItemChecked = true;
                    selectedUnitTypes.Add(data.FilterTypeId);
                }
                FacilityList = new ObservableCollection<FilterData>(fList);
            }

            if (UnitTypeList != null && UnitTypeList.Count > 0)
            {
                fList = new List<FilterData>(UnitTypeList);
                foreach (FilterData data in fList)
                {
                    data.ItemChecked = true;
                    selectedUnitTypes.Add(data.FilterTypeId);
                }
                UnitTypeList = new ObservableCollection<FilterData>(fList);
            }
        }

        public void CheckAllLsdFilterData()
        {
            selectedLsdFluids = new List<string>();
            selectedLsdUnitTypes = new List<string>();
            List<FilterData> fList = new List<FilterData>();

            if (LsdFluidList != null && LsdFluidList.Count > 0)
            {
                fList = new List<FilterData>(LsdFluidList);
                foreach (FilterData data in fList)
                {
                    data.ItemChecked = true;
                    selectedLsdFluids.Add(data.FilterTypeId);
                }
                LsdFluidList = new ObservableCollection<FilterData>(fList);
            }

            if (LsdFacilityList != null && LsdFacilityList.Count > 0)
            {
                fList = new List<FilterData>(LsdFacilityList);
                foreach (FilterData data in fList)
                {
                    data.ItemChecked = true;
                    selectedLsdUnitTypes.Add(data.FilterTypeId);
                }
                LsdFacilityList = new ObservableCollection<FilterData>(fList);
            }

            if (LsdUnitTypeList != null && LsdUnitTypeList.Count > 0)
            {
                fList = new List<FilterData>(LsdUnitTypeList);
                foreach (FilterData data in fList)
                {
                    data.ItemChecked = true;
                    selectedLsdUnitTypes.Add(data.FilterTypeId);
                }
                LsdUnitTypeList = new ObservableCollection<FilterData>(fList);
            }
        }

        #endregion

        #region Check uncheck all
        private void CheckUnCheckAll(CheckBox chkAll)
        {
            if (ServiceLocator.Get<MainPageVM>().IsImportChecked)
            {
                if (AllCheckedUnchecked)
                    CheckAllFilterData();
                else
                    ResetFilterData();
            }
            else
            {
                if (AllLsdCheckedUnchecked)
                    CheckAllLsdFilterData();
                else
                    ResetLsdFilterData();
            }
        }
        #endregion

        #region Fluid Filter
        private void FluidFilter(CheckBox chkFluid)
        {
            string fluidType = Convert.ToString(chkFluid.Tag);
            if (!string.IsNullOrEmpty(fluidType))
            {
                if (ServiceLocator.Get<MainPageVM>().IsImportChecked)
                {
                    if (Convert.ToBoolean(chkFluid.IsChecked) && !selectedFluids.Contains(fluidType))
                        selectedFluids.Add(fluidType);
                    else
                        selectedFluids.Remove(fluidType);
                }
                else
                {
                    if (Convert.ToBoolean(chkFluid.IsChecked) && !selectedLsdFluids.Contains(fluidType))
                        selectedLsdFluids.Add(fluidType);
                    else
                        selectedLsdFluids.Remove(fluidType);
                }
            }
            if (ServiceLocator.Get<MainPageVM>().IsImportChecked)
            {
                if (selectedFluids != null && selectedFluids.Count == 0 && selectedUnitTypes != null && selectedUnitTypes.Count == 0)
                    AllCheckedUnchecked = false;
                else
                    AllCheckedUnchecked = true;
            }
            else
            {
                if (selectedLsdFluids != null && selectedLsdFluids.Count == 0 && selectedLsdUnitTypes != null && selectedLsdUnitTypes.Count == 0)
                    AllLsdCheckedUnchecked = false;
                else
                    AllLsdCheckedUnchecked = true;
            }
        }
        #endregion

        #region UnitType Filter
        private void UnitTypeFilter(CheckBox chkUnitType)
        {
            string unitType = Convert.ToString(chkUnitType.Tag);
            if (!string.IsNullOrEmpty(unitType))
            {
                if (ServiceLocator.Get<MainPageVM>().IsImportChecked)
                {
                    if (Convert.ToBoolean(chkUnitType.IsChecked) && !selectedUnitTypes.Contains(unitType))
                        selectedUnitTypes.Add(unitType);
                    else
                        selectedUnitTypes.Remove(unitType);
                }
                else
                {
                    if (Convert.ToBoolean(chkUnitType.IsChecked) && !selectedLsdUnitTypes.Contains(unitType))
                        selectedLsdUnitTypes.Add(unitType);
                    else
                        selectedLsdUnitTypes.Remove(unitType);
                }
            }
            if (ServiceLocator.Get<MainPageVM>().IsImportChecked)
            {
                if (selectedFluids != null && selectedFluids.Count == 0 && selectedUnitTypes != null && selectedUnitTypes.Count == 0)
                    AllCheckedUnchecked = false;
                else
                    AllCheckedUnchecked = true;
            }
            else
            {
                if (selectedLsdFluids != null && selectedLsdFluids.Count == 0 && selectedLsdUnitTypes != null && selectedLsdUnitTypes.Count == 0)
                    AllLsdCheckedUnchecked = false;
                else
                    AllLsdCheckedUnchecked = true;
            }
        }
        #endregion

        #region Filter by Compressor
        private void FilterByCombinedTower(CheckBox chkCT)
        {
            IsCombinedTowerChecked = Convert.ToBoolean(chkCT.IsChecked) ? true : false;
            if (OnCombinedTowerClick != null)
                OnCombinedTowerClick(this, null);

            //ServiceLocator.Get<ShutdownMngVM>().FilteredLSDLocations = from item in ServiceLocator.Get<ShutdownMngVM>().LinkedShutdownLocations

        }
        #endregion

        #region Validation
        protected void NotifyPropertyChanged(Expression<Func<object>> propertyExpression)
        {
            if (propertyExpression == null)
                throw new ArgumentNullException(FIFPConstants.propertyExpression);

            var propertyName = GetPropertyName(propertyExpression);
            OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            Validate(propertyName);
            OnNotifyPropertyChanged();
        }

        protected virtual void OnNotifyPropertyChanged() { }

        private string GetPropertyName(Expression<Func<object>> propertyExpression)
        {
            var unaryExpression = propertyExpression.Body as UnaryExpression;
            var memberExpression = unaryExpression == null ? (MemberExpression)propertyExpression.Body : (MemberExpression)unaryExpression.Operand;

            var propertyName = memberExpression.Member.Name;

            return propertyName;
        }


        private void NotifyErrorsChanged(string propertyName)
        {
            ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }

        protected void Validate(string propertyName)
        {
            var value = GetPropertyValue(propertyName);
            RemoveErrorsForProperty(propertyName);
            Validator.TryValidateProperty(value, new ValidationContext(this, null, null) { MemberName = propertyName }, _validationResults);
            NotifyErrorsChanged(propertyName);
        }

        protected void Validate()
        {
            _validationResults.Clear();
            Validator.TryValidateObject(this, new ValidationContext(this, null, null), _validationResults, true);

            foreach (var result in _validationResults)
                NotifyErrorsChanged(result.MemberNames.First());

        }

        private object GetPropertyValue(string propertyName)
        {
            var type = this.GetType();

            var propertyInfo = type.GetProperty(propertyName);

            if (propertyInfo == null)
            {
                throw new ArgumentException(string.Format(FIFPConstants.Couldntfindanyproperty, propertyName, type));
            }

            return propertyInfo.GetValue(this, null);
        }

        private void RemoveErrorsForProperty(string propertyName)
        {
            var validationResults = _validationResults.Where(result => result.MemberNames.Contains(propertyName)).ToList();

            foreach (var result in validationResults)
                _validationResults.Remove(result);
        }

        public IEnumerable GetErrors(string propertyName)
        {
            return _validationResults.Where(result => result.MemberNames.Contains(propertyName));
        }

        public bool HasErrors
        {
            get { return _validationResults.Any(); }
        }

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        //public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}
